package com.yunshipei.common;

import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;

import com.yunshipei.common.net.converter.JsonConverterFactory;
import com.yunshipei.core.common.XCloudException;
import com.yunshipei.core.net.EnterClient;
import com.yunshipei.core.utils.CommonUtils;
import com.yunshipei.core.utils.FileUtils;
import com.yunshipei.core.utils.SystemUtils;
import com.yunshipei.db.green.XCloudSign;
import com.yunshipei.db.green.XCloudSignDao;
import com.yunshipei.manager.EnterDbManager;
import com.yunshipei.manager.YspPreferences;
import com.yunshipei.model.MainExtraBean;
import com.yunshipei.model.SSOSModel;
import com.yunshipei.model.UserInfo;
import com.yunshipei.utils.EncUtils;

import org.json.JSONObject;
import org.reactivestreams.Publisher;

import java.io.File;
import java.io.InputStream;
import java.util.List;

import io.reactivex.Flowable;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.http.GET;
import retrofit2.http.Streaming;
import retrofit2.http.Url;

/**
 * 首页包下载逻辑处理：新旧版本的兼容
 * <p>
 * Enterplorer登录接口数据处理与解析
 */
public class ProfileHandler {

    public static final String H5_LOGIN_PAGE_VERSION = "_h5_login_version";
    public static final String H5_PKG_CONFIG = "_ysp_h5_cfg";
    private static final String HOME_PAGE = "homePage";

    private Context mContext;
    private JSONObject mData;
    private String mManagerServer;
    private String mPassword;
    private SharedPreferences mPreferences;
    private Api mApi;
    private SharedPreferences mCfgPreference;

    public ProfileHandler(Context mContext, JSONObject mData, String mManagerServer, String password) {
        this.mContext = mContext;
        this.mData = mData;
        this.mManagerServer = mManagerServer;
        this.mPreferences = YspPreferences.getInstance().getSharedPreferences();
        this.mPassword = password;
        this.mCfgPreference = mContext.getSharedPreferences(H5_PKG_CONFIG, Context.MODE_PRIVATE);
        OkHttpClient okHttpClient = EnterClient.getInstances().getManagerClient();
        this.mApi = new Retrofit.Builder().baseUrl(mManagerServer).client(okHttpClient).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).addConverterFactory(JsonConverterFactory.create()).build().create(Api.class);
    }

    public Flowable<MainExtraBean> start() {
        return Flowable.just(mData).flatMap(new Function<JSONObject, Publisher<Boolean>>() {
            @Override
            public Publisher<Boolean> apply(JSONObject jsonObject) throws Exception {
                JSONObject dataObject = mData.optJSONObject("data");
                if (dataObject != null) {
                    int managerCode = dataObject.optInt("managerCode", 0);
                    if (managerCode < 2) {
                        return homePageFlowable(dataObject);
                    } else {
                        Flowable<Boolean> homePage = homePageFlowable(dataObject);
                        Flowable<String> loginPage = loginPageFlowable(dataObject);
                        return Flowable.zip(homePage, loginPage, new BiFunction<Boolean, String, Boolean>() {
                            @Override
                            public Boolean apply(Boolean aBoolean, String s) throws Exception {
                                return true;
                            }
                        });
                    }
                } else {
                    return Flowable.error(new XCloudException("接口异常，data为null"));
                }
            }
        }).flatMap(new Function<Boolean, Publisher<MainExtraBean>>() {
            @Override
            public Publisher<MainExtraBean> apply(Boolean b) throws Exception {
                String result = mData.toString();
                String dataJs = mData.optJSONObject("data").optJSONObject("datajsApps").toString();
                MainExtraBean mainExtraBean = new UserLoginDataParser(mContext).parse(result, dataJs);
                if (mainExtraBean == null) {
                    return Flowable.error(new XCloudException("接口数据异常"));
                }
                return Flowable.just(mainExtraBean);
            }
        }).flatMap(new Function<MainExtraBean, Publisher<MainExtraBean>>() {
            @Override
            public Publisher<MainExtraBean> apply(MainExtraBean mainExtraBean) throws Exception {
                //处理统一登录认证，统一登录认证的数据，只需要在登录的时候保存一次
                UserInfo userInfo = mainExtraBean.getUserInfo();
                List<SSOSModel> ssosModels = mainExtraBean.getSsosModels();
                if (ssosModels != null) {
                    for (SSOSModel ssosModel : ssosModels) {
                        String userLoginType = ssosModel.userLoginType;
                        if (!TextUtils.isEmpty(userLoginType) && "Unify".equalsIgnoreCase(userLoginType)) {
                            String ssoLoginName = "";
                            String flag = ssosModel.userLoginFlag;
                            String email = userInfo.getEmail();
                            if ("Email".equals(flag)) {
                                ssoLoginName = email;
                            } else if ("EmailPrefixes".equals(flag)) {
                                ssoLoginName = email.substring(0, email.indexOf("@"));
                            } else if ("PhoneNumbers".equals(flag)) {
                                ssoLoginName = userInfo.getTel();
                            }
                            String host = CommonUtils.getHost(ssosModel.address);
                            if (!TextUtils.isEmpty(ssoLoginName) && !TextUtils.isEmpty(host)) {
                                int type = ssosModel.type;
                                XCloudSignDao dao = EnterDbManager.getInstances().getXCloudSignDao();
                                XCloudSign xCloudSign = dao.queryBuilder().where(XCloudSignDao.Properties.Host.eq(host)).build().unique();
                                String uuid = userInfo.getUuid();
                                String encLoginName = EncUtils.encrypt(uuid, ssoLoginName.getBytes());
                                String encPass = EncUtils.encrypt(uuid, mPassword.getBytes());
                                if (!TextUtils.isEmpty(encLoginName) && !TextUtils.isEmpty(encPass)) {
                                    if (xCloudSign == null) {
                                        xCloudSign = new XCloudSign(host, encLoginName, encPass, String.valueOf(type), "", "");
                                        dao.insert(xCloudSign);
                                    } else {
                                        xCloudSign = new XCloudSign(host, encLoginName, encPass, String.valueOf(type), "", "");
                                        dao.update(xCloudSign);
                                    }
                                }
                            }
                        }
                    }
                }
                return Flowable.just(mainExtraBean);
            }
        });
    }

    //h5版的登录页的本地资源包
    private Flowable<String> loginPageFlowable(final JSONObject dataObject) {
        return Flowable.just(true).flatMap(new Function<Boolean, Publisher<String>>() {
            @Override
            public Publisher<String> apply(Boolean aBoolean) throws Exception {
                int managerCode = dataObject.optInt("managerCode", 0);
                if (managerCode < 2) {
                    return Flowable.just("");
                }
                JSONObject dataJsObject = dataObject.optJSONObject("datajsApps");
                JSONObject incrementObject = dataJsObject.optJSONObject("incrementalVersions");
                JSONObject loginPageObject = null;
                if (incrementObject != null) {
                    loginPageObject = incrementObject.optJSONObject("enterplorerLoginpage");
                }
                if (loginPageObject == null) {
                    return Flowable.error(new XCloudException("缺少登录页面数据"));
                }
                final int newVersion = loginPageObject.optInt("incrementalVersion", 0);
                String downloadUrl = loginPageObject.optString("downloadUrl", "");
                if (!downloadUrl.startsWith("http://") && !downloadUrl.startsWith("https://")) {
                    downloadUrl = mManagerServer + File.separator + downloadUrl;
                }
                String resJSON = FileUtils.readAssertResource(mContext, "local/localResCfg.json");
                if (TextUtils.isEmpty(resJSON)) {
                    return Flowable.error(new XCloudException("获取本地登录包资源文件的配置失败"));
                }
                JSONObject localCfgObject = new JSONObject(resJSON);
                int localVersion = localCfgObject.optInt("loginpage", 0);
                if (newVersion <= localVersion) {
                    return Flowable.just("file:///android_asset/local/loginpage/index.html");
                }
                //下载最新的通讯录
                int contactVersion = mCfgPreference.getInt(H5_LOGIN_PAGE_VERSION, 0);
                File indexFile = new File(mContext.getFilesDir().getParent() + File.separator + "web_login" + File.separator + "index.html");
                if (0 == contactVersion || newVersion != contactVersion || !indexFile.exists()) {
                    return mApi.commonDownload(downloadUrl).flatMap(new Function<Response<ResponseBody>, Publisher<String>>() {
                        @Override
                        public Publisher<String> apply(Response<ResponseBody> response) throws Exception {
                            int code = response.code();
                            if (code != 200) {
                                return Flowable.error(new XCloudException(response.message()));
                            }
                            File newFile = new File(mContext.getFilesDir().getParent() + File.separator + "web_login_temp");
                            boolean success = FileUtils.unZipStream(response.body().byteStream(), newFile.getPath());
                            if (success) {
                                InputStream is = mContext.getAssets().open("local/loginpage/loginVendor.js");
                                boolean isSuccess = FileUtils.writeToFile(newFile.getPath(), "loginVendor.js", is);
                                if (isSuccess) {
                                    File finalFile = new File(mContext.getFilesDir().getParent() + File.separator + "web_login");
                                    FileUtils.deletePathReal(finalFile.getPath());
                                    boolean rename = newFile.renameTo(finalFile);
                                    if (rename) {
                                        mCfgPreference.edit().putInt(H5_LOGIN_PAGE_VERSION, newVersion).apply();
                                        return Flowable.just("file://" + finalFile.getAbsolutePath() + File.separator + "index.html");
                                    } else {
                                        return Flowable.error(new XCloudException("登录包重命名失败"));
                                    }
                                } else {
                                    return Flowable.error(new XCloudException("登录包通用资源复制失败"));
                                }
                            } else {
                                return Flowable.error(new XCloudException("登录包资源解压失败..."));
                            }
                        }
                    }).doOnError(new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) throws Exception {
                            FileUtils.deletePathReal(mContext.getFilesDir().getParent() + File.separator + "web_login_temp");
                        }
                    });
                } else {
                    return Flowable.just("file://" + mContext.getFilesDir().getParent() + File.separator + "web_login" + File.separator + "index.html");
                }
            }
        });
    }

    //首页包的处理，包括新旧版兼容问题
    private Flowable<Boolean> homePageFlowable(final JSONObject dataObject) {
        return Flowable.just(true).flatMap(new Function<Boolean, Publisher<String>>() {
            @Override
            public Publisher<String> apply(Boolean aBoolean) throws Exception {
                JSONObject incVerObject = null;
                JSONObject dataJSObject = dataObject.optJSONObject("datajsApps");
                if (dataJSObject != null) {
                    incVerObject = dataJSObject.optJSONObject("incrementalVersions");
                }
                if (incVerObject != null) {
                    JSONObject homePageObject;
                    if (SystemUtils.isPad(mContext)) {
                        homePageObject = incVerObject.optJSONObject("enterplorerPadHomepage");
                    } else {
                        homePageObject = incVerObject.optJSONObject("enterplorerHomepage");
                    }
                    if (homePageObject != null) {
                        return homePagePrepare(homePageObject);
                    } else {
                        return Flowable.error(new XCloudException("没有首页包，请联系管理员..."));
                    }
                } else {
                    String homePageUrl = dataObject.optString("homepage");
                    if (!TextUtils.isEmpty(homePageUrl)) {
                        //使用旧版首页包
                        return homePagePrepare(homePageUrl);
                    } else {
                        return Flowable.error(new XCloudException("没有首页包，请联系管理员..."));
                    }
                }
            }
        }).flatMap(new Function<String, Publisher<Boolean>>() {
            @Override
            public Publisher<Boolean> apply(String homePageVersion) throws Exception {
                mPreferences.edit().putString(Globals.VERSION_YSP_INCREMENTAL_HOME_PAGE, homePageVersion).apply();
                return Flowable.just(true);
            }
        });
    }

    //新版首页包下载处理逻辑
    private Flowable<String> homePagePrepare(JSONObject homePageObject) {
        final String homePageVersion = homePageObject.optString("incrementalVersion");
        String homePageUrl = homePageObject.optString("downloadUrl");
        if (!TextUtils.isEmpty(homePageVersion) && !TextUtils.isEmpty(homePageUrl)) {
            String lastHomePageVersion = mPreferences.getString(Globals.VERSION_YSP_INCREMENTAL_HOME_PAGE, "");
            File hisFile = new File(mContext.getFilesDir().getPath() + File.separator + Globals.APP_WEB_ROOT_PATH + File.separator + HOME_PAGE + homePageVersion);
            if (TextUtils.isEmpty(lastHomePageVersion) || !homePageVersion.equals(lastHomePageVersion) || !hisFile.exists()) {
                //开始下载
                String downloadUrl;
                if (homePageUrl.startsWith("http://") || homePageUrl.startsWith("https://")) {
                    downloadUrl = homePageUrl;
                } else {
                    downloadUrl = mManagerServer + File.separator + homePageUrl;
                }
                return mApi.commonDownload(downloadUrl).flatMap(new Function<Response<ResponseBody>, Publisher<String>>() {
                    @Override
                    public Publisher<String> apply(Response<ResponseBody> response) throws Exception {
                        int code = response.code();
                        if (code == 200) {
                            String rootPath = mContext.getFilesDir().getPath() + File.separator + Globals.APP_WEB_ROOT_PATH;
                            String downloadPath = rootPath + File.separator + "download";
                            boolean saveSuccess = FileUtils.unZipStream(response.body().byteStream(), downloadPath);
                            if (saveSuccess) {
                                String newFileNamePath = rootPath + File.separator + HOME_PAGE + homePageVersion;
                                File newFile = new File(newFileNamePath);
                                if (newFile.exists()) {
                                    FileUtils.deletePathReal(newFileNamePath);
                                }
                                File downloadFile = new File(downloadPath);
                                boolean reRename = downloadFile.renameTo(newFile);
                                if (reRename) {
                                    File[] allFiles = new File(rootPath).listFiles();
                                    for (File tempFile : allFiles) {
                                        String tempFileName = tempFile.getName();
                                        if ((HOME_PAGE + homePageVersion).equals(tempFileName) || Globals.YSP_NEW_ADAPTER_PAC_PATH.equals(tempFileName)) {
                                            continue;
                                        }
                                        FileUtils.deleteFile(tempFile);
                                    }
                                    InputStream inputStream = mContext.getAssets().open("vendor.js");
                                    boolean saveVendor = FileUtils.writeToFile(newFile.getPath(), "vendor.js", inputStream);
                                    if (!saveVendor) {
                                        return Flowable.error(new XCloudException("react文件保存失败"));
                                    }
                                    return Flowable.just(homePageVersion);
                                } else {
                                    return Flowable.error(new XCloudException("首页包重命名失败..."));
                                }
                            } else {
                                return Flowable.error(new XCloudException("首页包保存失败..."));
                            }
                        }
                        return Flowable.error(new XCloudException("首页包请求出错，错误码:" + code));
                    }
                }).doOnError(new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        String rootPath = mContext.getFilesDir().getPath() + File.separator + Globals.APP_WEB_ROOT_PATH;
                        String downloadPath = rootPath + File.separator + "download";
                        FileUtils.deletePathReal(downloadPath);
                    }
                });
            } else {
                return Flowable.just(homePageVersion);
            }
        } else {
            return Flowable.error(new XCloudException("homePage字段错误..."));
        }
    }

    /**
     * 旧版首页包处理逻辑
     * 如果首页包是旧版的，首页包和适配包是在一起的，在下载解压适配包的时候首页包资源已经下载解压保存了，所以此时不需要再次下载，
     * 只需要将其他多余的包删除就可以了
     */
    private Flowable<String> homePagePrepare(String url) {
        return Flowable.just(url).flatMap(new Function<String, Publisher<String>>() {
            @Override
            public Publisher<String> apply(String url) throws Exception {
                String homePageResDir = url.substring(url.lastIndexOf("/") + 1).replace(".zip", "");
                String rootPath = mContext.getFilesDir().getPath() + File.separator + Globals.APP_WEB_ROOT_PATH;
                File[] allFiles = new File(rootPath).listFiles();
                for (File tempFile : allFiles) {
                    String tempFileName = tempFile.getName();
                    if ((homePageResDir).equals(tempFileName) || Globals.YSP_NEW_ADAPTER_PAC_PATH.equals(tempFileName)) {
                        continue;
                    }
                    FileUtils.deleteFile(tempFile);
                }
                return Flowable.just("");
            }
        });
    }

    private interface Api {
        @GET
        @Streaming
        Flowable<Response<ResponseBody>> commonDownload(@Url String url);
    }
}
